/*
 *
 * Author: Allan <qimingos_lsk@163.com>, (C) 2005-2007
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 */

#include <dlfcn.h>
#include <audacious/plugin.h>
#include <audacious/input.h>
#include "include/ShowLyric.h"
#include "include/AudaPlugin.h"

GeneralPlugin lyric_gp =
{ 	.description = PLUGIN_NAME,
	.init = lyric_init,
	.about = lyric_about,
	.configure = lyric_prefs,
	.cleanup = lyric_cleanup,
};

GeneralPlugin *lyric_gplist[] =
{ &lyric_gp, NULL, };

//DECLARE_PLUGIN(ShowLyric, NULL, NULL, NULL, NULL, NULL, lyric_gplist, NULL, NULL);
SIMPLE_GENERAL_PLUGIN(ShowLyric, lyric_gplist);

void lyric_about()
{
	theApp.About(NULL);
}

void lyric_init()
{
	LyricDebug("lyric_init");

	aud_hook_associate("playback begin", lyric_playback_begin, NULL);
	theApp.m_player.LoadConfigs = Lyric_LoadConfigs;
	theApp.m_player.SaveConfigs = Lyric_SaveConfigs;
	theApp.m_player.GetCurrTime = Lyric_GetCurrTime;
	theApp.m_player.GetSongInfo = Lyric_GetSongInfo;
	theApp.m_player.Str2UTF8 = Lyric_Str2UTF8;
	theApp.m_player.IsCurrSong = Lyric_IsCurrSong;
	theApp.m_player.GetSongTime = Lyric_GetSongTime;

	// 搜索引擎
	theApp.m_player.GetSearchAppCount = Lyric_GetSearchAppCount;
	theApp.m_player.GetSearchApp = Lyric_GetSearchApp;
	theApp.m_player.SetSearchApp = Lyric_SetSearchApp;

	theApp.Init();
}
gint Lyric_GetCurrTime()
{
	return audacious_drct_get_time();
}

gint Lyric_GetSongTime()
{
	return audacious_drct_get_length();
}

void lyric_prefs()
{
	theApp.ShowConfigDlg();
}

void lyric_cleanup()
{
	Lyric_SaveConfigs(&theApp.m_configs);
	theApp.Clean();
}

void lyric_playback_begin(gpointer unused, gpointer unused2)
{
	LyricDebug("lyric_playback_begin");

	// 获取当前播放的歌曲信息
	SongInfo info;
	if (!Lyric_GetSongInfo(&info))
		return;

	if (!theApp.PreChangeSong(&info))
		return;

	theApp.ChangeSong(info);
}

gboolean Lyric_IsCurrSong(SongInfo info)
{
	SongInfo infoCurr;
	memset(&infoCurr, 0, sizeof(infoCurr));
	if (!Lyric_GetSongInfo(&infoCurr))
	{
		return FALSE;
	}
	return (strcmp(infoCurr.szFileName, info.szFileName) == 0);
}

gboolean Lyric_GetSongInfo(SongInfo * pInfo)
{
	gchar *pszTitle= NULL, *pszArtist= NULL, *lpszTmp= NULL;
	Playlist *pl= NULL;
	int iPlPos = 0;
	if (!audacious_drct_get_playing())
		return FALSE;
	gint iPlLen= audacious_drct_pl_get_length();

	if (iPlLen <= 0)
	{
		return FALSE;
	}

	iPlPos = audacious_drct_pl_get_pos();
	if (iPlPos < 0)
	{
		return FALSE;
	}
	Tuple *out = NULL;
	gint iLen = 0;

	pl = aud_playlist_get_active();
	out = aud_playlist_get_tuple(pl, iPlPos);
	if (!out)
	{
		return FALSE;
	}
	iLen = aud_tuple_get_int(out, FIELD_LENGTH, NULL);
	if (iLen < 1)
	{
		LyricLog("The song's tuple is empty!\n");
		return FALSE;
	}

	// 获取文件完整路径名
	lpszTmp = aud_playlist_get_filename(pl, iPlPos);
	if (!lpszTmp)return FALSE;
	gchar * lpszFileName = g_filename_from_uri(lpszTmp, NULL, NULL);
	g_free(lpszTmp);

	// 获取文件名
	lpszTmp = g_path_get_basename(lpszFileName);
	strncpy(pInfo->szFileName, lpszTmp, MAX_PATH);
	g_free(lpszTmp);

	// 获取目录名
	lpszTmp = g_path_get_dirname(lpszFileName);
	strncpy(pInfo->szSongFolder, lpszTmp, MAX_PATH);
	g_free(lpszTmp);

	g_free(lpszFileName);
	lpszFileName = NULL;

	// 获取歌曲标题
	pszTitle = (gchar *) aud_tuple_get_string(out, FIELD_TITLE, NULL);
	if (pszTitle)
	{
		strncpy(pInfo->szTitle, pszTitle, TITLE_LENGTH);

		pInfo->szTitle[TITLE_LENGTH] = 0;
		pszTitle = NULL;
	}
	else
	{
		int iLenght = strlen((const char *) pInfo->szFileName);
		int iDotPos = iLenght, iNameBegin = 0, iCurr = iLenght;

		while (iCurr> 0)
		{
			if (pInfo->szFileName[iCurr] == '.' && iDotPos == iLenght)
			{
				iDotPos = iCurr;
				iCurr--;
				continue;
			}
			if (pInfo->szFileName[iCurr] == '.')
			{
				iNameBegin = iCurr + 2;
				if (iNameBegin != iDotPos)
				break;
			}
			iCurr--;
		}
		int iTitleLen = iDotPos - iNameBegin;
		LyricDebug ("iDotPos:%d, iNameBegin:%d, iTitleLen:%d, iLenght:%d",
		iDotPos, iNameBegin, iTitleLen, strlen((const char *) pInfo->szFileName));
		if (iTitleLen <= 0)
		return FALSE;
		strncpy(pInfo->szTitle, pInfo->szFileName + iNameBegin, iTitleLen);
		pInfo->szTitle[iTitleLen] = '\0';
	}

	// 获取歌曲作者
	pszArtist = (gchar *) aud_tuple_get_string(out, FIELD_ARTIST, NULL);
	if (pszArtist)
	{
		strncpy(pInfo->szArtist, pszArtist, ARTIST_LENGTH);
		pInfo->szArtist[ARTIST_LENGTH] = '\0';
		//free(pszArtist);
		pszArtist = NULL;
	}
	else
	{
		pInfo->szArtist[0] = 0;
	}

	// 由于Audacious提供的信息可能不正确，所以我们需要根据对歌曲标题和作者进行修复
	if(g_strstr_len(pInfo->szTitle, strlen(pInfo->szTitle), "????"))
	{
		gchar szTmp[MAX_PATH] = {0};
		gchar* lpszName = GetNameFromFileName(pInfo->szFileName, szTmp, MAX_PATH);
		// 如果存在乱码，那么就拿文件名当歌曲的标题
		strncpy(pInfo->szTitle, lpszName, MAX_PATH);
	}

	if(g_strstr_len(pInfo->szArtist, strlen(pInfo->szArtist), "????"))
	{
		// 如果存在乱码，那么清空。
		// 因为作者不是必须的关键字
		memset(pInfo->szArtist, 0, sizeof(pInfo->szArtist));
	}

	gchar szName[MAX_PATH] = {0};
	if (theApp.m_configs.bSaveLyricToSongFolder)
	{
		if (theApp.m_configs.bSaveLyricAsFileName)
		{
			snprintf(pInfo->szLyricFileName, MAX_PATH, "%s/%s.lrc", pInfo->szSongFolder, GetNameFromFileName(pInfo->szFileName, szName, MAX_PATH));
		}
		else
		{
			snprintf(pInfo->szLyricFileName, MAX_PATH, "%s/%s - %s.lrc", pInfo->szSongFolder, pInfo->szArtist, pInfo->szTitle);
		}
	}
	else
	{
		if (theApp.m_configs.bSaveLyricAsFileName)
		{
			snprintf(pInfo->szLyricFileName, MAX_PATH, "%s/%s.lrc", theApp.m_configs.szLyricPath, GetNameFromFileName(pInfo->szFileName, szName, MAX_PATH));
		}
		else
		{
			snprintf(pInfo->szLyricFileName, MAX_PATH, "%s/%s/%s.lrc", theApp.m_configs.szLyricPath, pInfo->szArtist, pInfo->szTitle);
		}
	}
	LyricDebug("szSongFolder: %s", pInfo->szSongFolder);
	LyricDebug("szFileName: %s", pInfo->szFileName);
	LyricDebug("szTitle:    %s", pInfo->szTitle);
	LyricDebug("szArtist:   %s", pInfo->szArtist);
	LyricDebug("szLyricFileName:   %s\n\n", pInfo->szLyricFileName);
	return TRUE;
}
// 加载配置信息
// @pConfigs： 配置信息
gboolean Lyric_LoadConfigs(OUT Configs* pConfigs)
{
	int iTmp = 0;
	// 加载配置信息
	ConfigDb *cfgfile = aud_cfg_db_open();

	gchar *lpszTmp= NULL;
	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "LyricPath", &lpszTmp))
	{
		strncpy(pConfigs->szLyricPath, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_int(cfgfile, PLUGIN_NAME, "SearchAppIndex", &iTmp))
		pConfigs->nSearchAppIndex = iTmp;

#define LOAD_COLOR(name, to) if(aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, name, &lpszTmp)) {\
		gdk_color_parse(lpszTmp, &to);\
	}

	LOAD_COLOR("BackgroundColor", pConfigs->colors.background);
	LOAD_COLOR("NormalColor", pConfigs->colors.normal);
	LOAD_COLOR("CurrColor", pConfigs->colors.current);
	LOAD_COLOR("DragColor", pConfigs->colors.drag);
	LOAD_COLOR("MsgColor", pConfigs->colors.msg);
	LOAD_COLOR("ErrorColor", pConfigs->colors.error);

	gboolean bTmp = FALSE;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "ShowWindowLyric", &bTmp))
		pConfigs->bShowWindowLyric = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "SmartShowWin", &bTmp))
		pConfigs->bSmartShowWin = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "SmartDownLoad", &bTmp))
		pConfigs->bSmartDownLoad = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "ShowBroad", &bTmp))
		pConfigs->bShowBroad = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "SaveLyricToSongFolder", &bTmp))
		pConfigs->bSaveLyricToSongFolder = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "SaveLyricAsFileName", &bTmp))
	{
		pConfigs->bSaveLyricAsFileName = bTmp;
	}

	if (aud_cfg_db_get_int(cfgfile, PLUGIN_NAME, "Opacity", &iTmp))
		pConfigs->iOpacity = iTmp;

	if (aud_cfg_db_get_int(cfgfile, PLUGIN_NAME, "Pos_iX", &iTmp))
		pConfigs->pos.iX = iTmp;

	if (aud_cfg_db_get_int(cfgfile, PLUGIN_NAME, "Pos_iY", &iTmp))
		pConfigs->pos.iY = iTmp;

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "LyricFontName", &lpszTmp))
	{
		strncpy(pConfigs->szLyricFontName, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "LyricEncode", &lpszTmp))
	{
		strncpy(pConfigs->szLyricEncode, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "ShowOSDLyric", &bTmp))
		pConfigs->bShowOSDLyric = bTmp;

	if (aud_cfg_db_get_bool(cfgfile, PLUGIN_NAME, "IsKaLaOK", &bTmp))
		pConfigs->bIsKaLaOK = bTmp;

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "OSD_fake_translucent_bg", &lpszTmp))
	{
		strncpy(pConfigs->OSD.fake_translucent_bg, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "OSD_vposition", &lpszTmp))
	{
		strncpy(pConfigs->OSD.vposition, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "OSD_halignment", &lpszTmp))
	{
		strncpy(pConfigs->OSD.halignment, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "OSD_animations", &lpszTmp))
	{
		strncpy(pConfigs->OSD.animations, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}

	if (aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, "OSD_font", &lpszTmp))
	{
		strncpy(pConfigs->OSD.szFontName, lpszTmp, MAX_PATH);
		g_free(lpszTmp);
		lpszTmp = NULL;
	}
		
	aud_cfg_db_close(cfgfile);
	return TRUE;
}


gint Lyric_GetSearchAppCount()
{
	int iTmp = 0;
	ConfigDb *cfgfile = aud_cfg_db_open();
	aud_cfg_db_get_int(cfgfile, PLUGIN_NAME, "SearchAppCount", &iTmp);
	aud_cfg_db_close(cfgfile);
	return iTmp;
}

gboolean Lyric_GetSearchApp(gint nIndex, AppInfo* pApp)
{
	if (nIndex >= Lyric_GetSearchAppCount()) return FALSE;

	ConfigDb *cfgfile = aud_cfg_db_open();
	gchar *lpszTmp= NULL;
	gchar szKey[200] = {0};
	sprintf(szKey, "SearchApp_App_%d", nIndex);
	aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, szKey, &lpszTmp);
	strncpy(pApp->szApp, lpszTmp, MAX_PATH);
	sprintf(szKey, "SearchApp_Name_%d", nIndex);
	aud_cfg_db_get_string(cfgfile, PLUGIN_NAME, szKey, &lpszTmp);
	strncpy(pApp->szName, lpszTmp, MAX_PATH);
	aud_cfg_db_close(cfgfile);
	return TRUE;
}

gboolean Lyric_SetSearchApp(gint nIndex, AppInfo app)
{
	if (nIndex > Lyric_GetSearchAppCount())return FALSE;

	ConfigDb *cfgfile = aud_cfg_db_open();
	gchar szKey[200] = {0};
	sprintf(szKey, "SearchApp_App_%d", nIndex);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, szKey, app.szApp);
	sprintf(szKey, "SearchApp_Name_%d", nIndex);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, szKey, app.szName);
	if (nIndex == Lyric_GetSearchAppCount())
	{
		aud_cfg_db_set_int(cfgfile, PLUGIN_NAME, "SearchAppCount", nIndex + 1);
	}
	aud_cfg_db_close(cfgfile);
	return TRUE;
}

// 保存配置信息
// @pConfigs： 配置信息
gboolean Lyric_SaveConfigs(IN Configs* pConfigs)
{
	// 保存配置信息
	ConfigDb *cfgfile = aud_cfg_db_open();

	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "LyricPath", pConfigs->szLyricPath);
	aud_cfg_db_set_int(cfgfile, PLUGIN_NAME, "SearchAppIndex", pConfigs->nSearchAppIndex);

#define SAVE_COLOR(name, color) do {\
		gchar* lpszColor = gdk_color_to_string (&color);\
		aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, name, lpszColor);\
		free(lpszColor);\
	}while(0)
	SAVE_COLOR("BackgroundColor", pConfigs->colors.background);
	SAVE_COLOR("NormalColor", pConfigs->colors.normal);
	SAVE_COLOR("CurrColor", pConfigs->colors.current);
	SAVE_COLOR("DragColor", pConfigs->colors.drag);
	SAVE_COLOR("MsgColor", pConfigs->colors.msg);
	SAVE_COLOR("ErrorColor", pConfigs->colors.error);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "ShowWindowLyric", pConfigs->bShowWindowLyric);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "IsKaLaOK", pConfigs->bIsKaLaOK);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "SmartShowWin", pConfigs->bSmartShowWin);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "ShowBroad", pConfigs->bShowBroad);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "SmartDownLoad", pConfigs->bSmartDownLoad);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "SaveLyricToSongFolder", pConfigs->bSaveLyricToSongFolder);
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "SaveLyricAsFileName", pConfigs->bSaveLyricAsFileName);
	aud_cfg_db_set_int(cfgfile, PLUGIN_NAME, "Opacity", pConfigs->iOpacity);
	aud_cfg_db_set_int(cfgfile, PLUGIN_NAME, "Pos_iX", pConfigs->pos.iX);
	aud_cfg_db_set_int(cfgfile, PLUGIN_NAME, "Pos_iY", pConfigs->pos.iY);

	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "LyricFontName", pConfigs->szLyricFontName);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "LyricEncode", pConfigs->szLyricEncode);
	
	aud_cfg_db_set_bool(cfgfile, PLUGIN_NAME, "ShowOSDLyric", pConfigs->bShowOSDLyric );
	
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "OSD_fake_translucent_bg", pConfigs->OSD.fake_translucent_bg);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "OSD_vposition", pConfigs->OSD.vposition);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "OSD_halignment", pConfigs->OSD.halignment);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "OSD_animations", pConfigs->OSD.animations);
	aud_cfg_db_set_string(cfgfile, PLUGIN_NAME, "OSD_font", pConfigs->OSD.szFontName);

	aud_cfg_db_close(cfgfile);
	return TRUE;
}

gchar * MyStr2UTF8(const gchar * lpszStr)
{
	gchar szEncodes[MAX_PATH] = {0};
	gchar* lpszEncode = szEncodes;
	strcpy(szEncodes, theApp.m_configs.szLyricEncode);
	int i = 0;
	for (i = 0; i < MAX_PATH; i++)
	{
		if(szEncodes[i] == ';' || szEncodes[i] == '|')
		{
			szEncodes[i] = 0;
		}

		if (szEncodes[i] == 0)
		{
			gchar * lpszUTF8 = g_convert(lpszStr, strlen(lpszStr), "UTF-8", lpszEncode, NULL, NULL, NULL);
			if (lpszUTF8 && g_utf8_validate(lpszUTF8, -1, NULL))
				return lpszUTF8;
			lpszEncode = &szEncodes[i + 1];
		}
	}
	return NULL;
}

gchar *Lyric_Str2UTF8(const gchar * lpszStr)
{
	gchar * lpszUTF8 = aud_str_to_utf8(lpszStr);
	if (lpszUTF8)
	{
		if(g_strstr_len(lpszUTF8, strlen(lpszUTF8), "??????"))
		{
			g_free(lpszUTF8);
			return MyStr2UTF8(lpszStr);
		}
		return lpszUTF8;
	}
	return g_convert(lpszStr, strlen(lpszStr), "UTF-8", "GBK", NULL, NULL, NULL);
}
